feat: Use @typegpu/gl as a fallback when @typegpu/three is made to generate GLSL - #2794
Conversation
|
pkg.pr.new packages benchmark commit |
Resolution Time Benchmark---
config:
themeVariables:
xyChart:
plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
title "Random Branching (🔴 PR | 🔵 main | 🟢 release)"
x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
y-axis "time (ms)"
line [0.42, 0.89, 1.98, 2.77, 3.18, 5.61, 10.43, 11.50]
line [0.44, 0.83, 1.93, 2.76, 3.53, 5.58, 10.79, 12.72]
line [0.45, 0.86, 1.81, 3.33, 3.57, 5.29, 10.51, 12.05]
---
config:
themeVariables:
xyChart:
plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
title "Linear Recursion (🔴 PR | 🔵 main | 🟢 release)"
x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
y-axis "time (ms)"
line [0.17, 0.27, 0.38, 0.41, 0.53, 0.53, 0.62, 0.70]
line [0.12, 0.23, 0.31, 0.41, 0.53, 0.56, 0.60, 0.72]
line [0.17, 0.27, 0.36, 0.42, 0.56, 0.50, 0.69, 0.74]
---
config:
themeVariables:
xyChart:
plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
title "Full Tree (🔴 PR | 🔵 main | 🟢 release)"
x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
y-axis "time (ms)"
line [0.48, 1.06, 2.18, 3.94, 5.82, 11.83, 24.66, 51.61]
line [0.47, 1.08, 2.17, 3.19, 5.65, 12.47, 25.49, 51.84]
line [0.51, 1.10, 2.01, 2.98, 5.95, 12.99, 26.04, 54.06]
|
Bundle size comparison (
|
| 🟢 Decreased (max -1.32%) | ➖ Unchanged | 🔴 Increased | ❔ Unknown |
|---|---|---|---|
| 285 | 37 | 0 | 0 |
import * as ... in PR vs import * as ... in target (did bundle size increase?):
Click to reveal the results table (187 entries).
| Test | tsdown |
|---|---|
| d_builtin.ts | 29.19 kB ( |
| d_matToArray.ts | 27.82 kB ( |
| d_mat2x2f.ts | 27.69 kB ( |
| d_mat3x3f.ts | 27.69 kB ( |
| d_mat4x4f.ts | 27.69 kB ( |
| std_identity4.ts | 27.69 kB ( |
| std_identity2.ts | 27.68 kB ( |
| std_identity3.ts | 27.68 kB ( |
| std_rotationX4.ts | 27.68 kB ( |
| std_rotationY4.ts | 27.68 kB ( |
| std_rotationZ4.ts | 27.68 kB ( |
| std_scaling4.ts | 27.68 kB ( |
| std_translation4.ts | 27.68 kB ( |
| std_textureLoad.ts | 26.64 kB ( |
| std_textureSample.ts | 26.64 kB ( |
| std_textureSampleBaseClampToEdge.ts | 26.64 kB ( |
| std_textureSampleBias.ts | 26.64 kB ( |
| std_textureSampleCompare.ts | 26.64 kB ( |
| std_textureSampleCompareLevel.ts | 26.64 kB ( |
| std_textureSampleGrad.ts | 26.64 kB ( |
| std_textureSampleLevel.ts | 26.64 kB ( |
| std_textureStore.ts | 26.64 kB ( |
| std_textureDimensions.ts | 26.63 kB ( |
| std_textureGather.ts | 26.63 kB ( |
| d_invariant.ts | 27.36 kB ( |
| d_interpolate.ts | 26.99 kB ( |
| d_location.ts | 26.98 kB ( |
| d_align.ts | 26.98 kB ( |
| d_size.ts | 26.98 kB ( |
| d_arrayOf.ts | 26.73 kB ( |
| std_bitcast.ts | 47.62 kB ( |
| std_bitcastU32toF32.ts | 47.61 kB ( |
| std_bitcastU32toI32.ts | 47.61 kB ( |
| std_bitcastF32toU32.ts | 47.61 kB ( |
| std_subgroupAll.ts | 25.03 kB ( |
| std_subgroupAnd.ts | 25.03 kB ( |
| std_subgroupAny.ts | 25.03 kB ( |
| std_subgroupBallot.ts | 25.03 kB ( |
| std_subgroupBroadcast.ts | 25.03 kB ( |
| std_subgroupBroadcastFirst.ts | 25.03 kB ( |
| std_subgroupElect.ts | 25.03 kB ( |
| std_subgroupExclusiveAdd.ts | 25.03 kB ( |
| std_subgroupExclusiveMul.ts | 25.03 kB ( |
| std_subgroupInclusiveAdd.ts | 25.03 kB ( |
| std_subgroupInclusiveMul.ts | 25.03 kB ( |
| std_subgroupMax.ts | 25.03 kB ( |
| std_subgroupMin.ts | 25.03 kB ( |
| std_subgroupMul.ts | 25.03 kB ( |
| std_subgroupOr.ts | 25.03 kB ( |
| std_subgroupShuffle.ts | 25.03 kB ( |
| std_subgroupShuffleDown.ts | 25.03 kB ( |
| std_subgroupShuffleUp.ts | 25.03 kB ( |
| std_subgroupShuffleXor.ts | 25.03 kB ( |
| std_subgroupXor.ts | 25.03 kB ( |
| std_subgroupAdd.ts | 25.02 kB ( |
| d_getLongestContiguousPrefix.ts | 25.31 kB ( |
| d_isContiguous.ts | 25.30 kB ( |
| d_sizeOf.ts | 25.29 kB ( |
| d_isBuiltin.ts | 25.24 kB ( |
| d_alignmentOf.ts | 22.51 kB ( |
| d_isPackedData.ts | 21.63 kB ( |
| d_packedFormats.ts | 21.59 kB ( |
| d_float16.ts | 21.57 kB ( |
| d_float16x2.ts | 21.57 kB ( |
| d_float16x4.ts | 21.57 kB ( |
| d_float32.ts | 21.57 kB ( |
| d_float32x2.ts | 21.57 kB ( |
| d_float32x3.ts | 21.57 kB ( |
| d_float32x4.ts | 21.57 kB ( |
| d_sint16.ts | 21.57 kB ( |
| d_sint16x2.ts | 21.57 kB ( |
| d_sint16x4.ts | 21.57 kB ( |
| d_sint32.ts | 21.57 kB ( |
| d_sint32x2.ts | 21.57 kB ( |
| d_sint32x3.ts | 21.57 kB ( |
| d_sint32x4.ts | 21.57 kB ( |
| d_sint8.ts | 21.57 kB ( |
| d_sint8x2.ts | 21.57 kB ( |
| d_sint8x4.ts | 21.57 kB ( |
| d_snorm16.ts | 21.57 kB ( |
| d_snorm16x2.ts | 21.57 kB ( |
| d_snorm16x4.ts | 21.57 kB ( |
| d_snorm8.ts | 21.57 kB ( |
| d_snorm8x2.ts | 21.57 kB ( |
| d_snorm8x4.ts | 21.57 kB ( |
| d_uint16.ts | 21.57 kB ( |
| d_uint16x2.ts | 21.57 kB ( |
| d_uint16x4.ts | 21.57 kB ( |
| d_uint32.ts | 21.57 kB ( |
| d_uint32x2.ts | 21.57 kB ( |
| d_uint32x3.ts | 21.57 kB ( |
| d_uint32x4.ts | 21.57 kB ( |
| d_uint8x2.ts | 21.57 kB ( |
| d_uint8x4.ts | 21.57 kB ( |
| d_unorm10_10_10_2.ts | 21.57 kB ( |
| d_unorm16.ts | 21.57 kB ( |
| d_unorm16x2.ts | 21.57 kB ( |
| d_unorm16x4.ts | 21.57 kB ( |
| d_unorm8.ts | 21.57 kB ( |
| d_unorm8x2.ts | 21.57 kB ( |
| d_unorm8x4.ts | 21.57 kB ( |
| d_unorm8x4_bgra.ts | 21.57 kB ( |
| d_uint8.ts | 21.56 kB ( |
| d_formatToWGSLType.ts | 21.56 kB ( |
| d_vec2b.ts | 20.07 kB ( |
| d_vec2f.ts | 20.07 kB ( |
| d_vec2h.ts | 20.07 kB ( |
| d_vec2i.ts | 20.07 kB ( |
| d_vec2u.ts | 20.07 kB ( |
| d_vec3b.ts | 20.07 kB ( |
| d_vec3f.ts | 20.07 kB ( |
| d_vec3h.ts | 20.07 kB ( |
| d_vec3i.ts | 20.07 kB ( |
| d_vec3u.ts | 20.07 kB ( |
| d_vec4b.ts | 20.07 kB ( |
| d_vec4f.ts | 20.07 kB ( |
| d_vec4h.ts | 20.07 kB ( |
| d_vec4i.ts | 20.07 kB ( |
| d_vec4u.ts | 20.07 kB ( |
| std_atomicAdd.ts | 16.69 kB ( |
| std_atomicAnd.ts | 16.69 kB ( |
| std_atomicMax.ts | 16.69 kB ( |
| std_atomicMin.ts | 16.69 kB ( |
| std_atomicOr.ts | 16.69 kB ( |
| std_atomicSub.ts | 16.69 kB ( |
| std_atomicXor.ts | 16.69 kB ( |
| std_storageBarrier.ts | 16.69 kB ( |
| std_workgroupBarrier.ts | 16.69 kB ( |
| std_atomicStore.ts | 16.69 kB ( |
| std_textureBarrier.ts | 16.69 kB ( |
| std_atomicLoad.ts | 16.68 kB ( |
| std_arrayLength.ts | 15.18 kB ( |
| std_dpdxCoarse.ts | 15.89 kB ( |
| std_dpdxFine.ts | 15.89 kB ( |
| std_dpdy.ts | 15.89 kB ( |
| std_dpdyCoarse.ts | 15.89 kB ( |
| std_dpdyFine.ts | 15.89 kB ( |
| std_fwidth.ts | 15.89 kB ( |
| std_fwidthCoarse.ts | 15.89 kB ( |
| std_fwidthFine.ts | 15.89 kB ( |
| std_dpdx.ts | 15.88 kB ( |
| std_copy.ts | 15.16 kB ( |
| d_disarrayOf.ts | 15.57 kB ( |
| std_discard.ts | 14.92 kB ( |
| std_range.ts | 15.40 kB ( |
| std_extensionEnabled.ts | 15.13 kB ( |
| std_getTargetShaderLanguage.ts | 15.08 kB ( |
| std_isBeingTranspiled.ts | 15.01 kB ( |
| d_textureMultisampled2d.ts | 14.10 kB ( |
| d_textureCubeArray.ts | 14.10 kB ( |
| d_texture2dArray.ts | 14.09 kB ( |
| d_textureDepthMultisampled2d.ts | 14.09 kB ( |
| d_textureDepthCubeArray.ts | 14.09 kB ( |
| d_textureDepth2dArray.ts | 14.08 kB ( |
| d_textureCube.ts | 14.08 kB ( |
| d_texture1d.ts | 14.08 kB ( |
| d_texture2d.ts | 14.08 kB ( |
| d_texture3d.ts | 14.08 kB ( |
| d_textureDepthCube.ts | 14.07 kB ( |
| d_textureDepth2d.ts | 14.06 kB ( |
| STATIC_allImports.ts | 295.42 kB ( |
| d_u16.ts | 13.64 kB ( |
| d_bool.ts | 13.62 kB ( |
| d_f16.ts | 13.62 kB ( |
| d_f32.ts | 13.62 kB ( |
| d_i32.ts | 13.62 kB ( |
| d_u32.ts | 13.62 kB ( |
| tgpu_resolveWithContext.ts | 269.65 kB ( |
| tgpu_bindGroupLayout.ts | 269.65 kB ( |
| tgpu_mutableAccessor.ts | 269.65 kB ( |
| tgpu_initFromDevice.ts | 269.65 kB ( |
| tgpu_vertexLayout.ts | 269.65 kB ( |
| tgpu_workgroupVar.ts | 269.65 kB ( |
| tgpu_fragmentFn.ts | 269.65 kB ( |
| tgpu_privateVar.ts | 269.65 kB ( |
| tgpu_computeFn.ts | 269.64 kB ( |
| tgpu_accessor.ts | 269.64 kB ( |
| tgpu_comptime.ts | 269.64 kB ( |
| tgpu_vertexFn.ts | 269.64 kB ( |
| tgpu_resolve.ts | 269.64 kB ( |
| tgpu_unroll.ts | 269.64 kB ( |
| tgpu_const.ts | 269.64 kB ( |
| tgpu_init.ts | 269.64 kB ( |
| tgpu_lazy.ts | 269.64 kB ( |
| tgpu_slot.ts | 269.64 kB ( |
| tgpu_fn.ts | 269.64 kB ( |
| STATIC_tgpu.ts | 269.63 kB ( |
import { ... } in PR vs import * as ... in PR (is the library tree-Shakeable?):
| Test | tsdown |
|---|---|
| tgpu_init.ts | 260.88 kB ( |
| tgpu_initFromDevice.ts | 260.35 kB ( |
| tgpu_resolve.ts | 167.50 kB ( |
| tgpu_resolveWithContext.ts | 167.44 kB ( |
| tgpu_bindGroupLayout.ts | 71.67 kB ( |
| tgpu_mutableAccessor.ts | 68.06 kB ( |
| tgpu_accessor.ts | 68.05 kB ( |
| tgpu_privateVar.ts | 66.80 kB ( |
| tgpu_workgroupVar.ts | 66.79 kB ( |
| tgpu_const.ts | 66.28 kB ( |
| tgpu_lazy.ts | 66.15 kB ( |
| tgpu_fn.ts | 38.59 kB ( |
| tgpu_fragmentFn.ts | 38.58 kB ( |
| tgpu_vertexFn.ts | 38.40 kB ( |
| tgpu_computeFn.ts | 38.10 kB ( |
| tgpu_vertexLayout.ts | 27.22 kB ( |
| tgpu_comptime.ts | 14.91 kB ( |
| tgpu_unroll.ts | 1.66 kB ( |
| tgpu_slot.ts | 1.54 kB ( |
If you wish to run a comparison for other, slower bundlers, run the 'Tree-shake test' from the GitHub Actions menu.
There was a problem hiding this comment.
Pull request overview
This PR updates @typegpu/three to support Three.js’s WebGL backend path by switching TypeGPU shader generation to GLSL via @typegpu/gl when WebGL is detected.
Changes:
- Add
@typegpu/glas a peer dependency and wire it into the workspace lockfile. - Detect WebGL backend in the node builder and apply
glOptions({ shaderStage: 'none' })totgpu.resolve(...)calls. - Adjust function-start detection to handle GLSL-style function declarations.
Reviewed changes
Copilot reviewed 2 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| pnpm-lock.yaml | Adds @typegpu/gl to the workspace install graph for packages/typegpu-three. |
| packages/typegpu-three/src/typegpu-node.ts | Adds WebGL detection + GLSL generation options via glOptions, and updates function-start detection. |
| packages/typegpu-three/package.json | Declares @typegpu/gl as a peer dependency for @typegpu/three. |
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| function isWebGL(builder: THREE.NodeBuilder): boolean { | ||
| return 'isWebGLBackend' in builder.renderer.backend && !!builder.renderer.backend.isWebGLBackend; | ||
| } |
| const lastFnStart = findFunctionStart(stageData.codeGeneratedThusFar, functionId, webgl); | ||
|
|
||
| // Extracting the function code | ||
| const fnCode = stageData.codeGeneratedThusFar.slice(lastFnStart).trim(); | ||
|
|
There was a problem hiding this comment.
Caution
The WebGL fallback path now generates GLSL, but forceExplicitVoidReturn is WGSL-only: it appends -> void after the first ), corrupting every GLSL function signature. This prevents the fallback from working. See the inline comment on packages/typegpu-three/src/typegpu-node.ts:193.
Reviewed changes
- Declared
@typegpu/glas a peer dependency and wiredglOptions({ shaderStage: 'none' })into the threetgpu.resolvecalls when the Three.js builder targets WebGL. - Added
isWebGL()backend detection andfindFunctionStart()to handle both WGSL (fn name) and GLSL (type name() function declaration syntax. - Refactored the dependency-assignment resolution in
generate()into a localcodevariable. - Updated
pnpm-lock.yamlto link the new peer dependency.
ℹ️ Docs will need updating once WebGL works
The @typegpu/three docs currently include a caution block stating that the WebGL fallback does not work. Once this feature branch makes it work, that block and the install instructions should be updated.
Kimi K2 (free via Pullfrog for OSS) | 𝕏
da61438 to
a010b4f
Compare
|
Follow-up to the review above with line-specific notes:
|
a010b4f to
2cc2d21
Compare
There was a problem hiding this comment.
Important
The @typegpu/gl delta improves GLSL emission, but the WebGL fallback path is still blocked because forceExplicitVoidReturn corrupts GLSL signatures.
Reviewed changes
Reviewed the delta that removed the WORKAROUND_wgslToGlslFixups post-processor from @typegpu/gl and replaced it with native GLSL generation.
- Removed
WORKAROUND_wgslToGlslFixupsfrompackages/typegpu-gl/src/tgpuRootWebGL.tsand its export inpackages/typegpu-gl/src/index.ts. - Added native array support in
packages/typegpu-gl/src/glslGenerator.ts:resolveArraySizeSuffix, array-awaredeclareGlobalConst,declareGlobalVar,typeAnnotation,typeInstantiation, and_emitVarDeclnow emit GLSLtype name[N]declarations andtype[N](...)constructors. - Added a
numericLiteraloverride that emits GLSL literals without WGSLf/hsuffixes, keepsuforu32, and chooses decimal or exponential form for floats. - Updated
@typegpu/gltest snapshots; all 35@typegpu/gltests pass.
⚠️ WebGL fallback remains broken for GLSL signatures
packages/typegpu-three/src/typegpu-node.ts:193 still applies forceExplicitVoidReturn(fnCode) unconditionally. The helper inserts -> void after the first ), which corrupts GLSL function signatures such as float foo() into float foo()-> void. This prevents the WebGL fallback from working even though @typegpu/gl now emits valid GLSL.
Technical details
# forceExplicitVoidReturn corrupts GLSL signatures
## Affected sites
- packages/typegpu-three/src/typegpu-node.ts:193 — `forceExplicitVoidReturn(fnCode)` is applied to GLSL code
## Required outcome
- GLSL function code must not be passed through the WGSL-specific `forceExplicitVoidReturn` helper.
## Suggested approach
Skip `forceExplicitVoidReturn` when `webgl` is true, or detect whether the resolved code already has a return type in a language-agnostic way.Kimi K2 (free via Pullfrog for OSS) | 𝕏
2cc2d21 to
7b889ba
Compare
7b889ba to
961d532
Compare
961d532 to
6b3dea9
Compare
6b3dea9 to
24d8fe3
Compare
24d8fe3 to
75504e6
Compare
There was a problem hiding this comment.
Caution
The upstream @typegpu/gl fixes in this rebase are correct, but the PR's own @typegpu/three integration still applies a WGSL-only helper to GLSL code. The WebGL fallback therefore remains broken.
Reviewed changes
Reviewed the delta from the previous pullfrog review head (6b3dea9) to the current head (75504e6). The @typegpu/three changes are byte-for-byte identical to the previous iteration; the new commits come from the upstream feat/make-triangle-work-with-gl-fallback feature branch.
- Eagerly reserved
gl_Positionandsampleinpackages/typegpu-gl/src/glslGenerator.tson the firstfunctionDefinitioncall, so theshaderStage: 'none'path used by@typegpu/threecannot accidentally use these GLSL keywords as identifiers. - Updated
@typegpu/glinline snapshots to match improved numeric-literal and zero-constructor emission (1i→1,0i→0,1.5f→1.5,vec3()→vec3(0)). - The
@typegpu/threefiles are unchanged from the previous iteration.
🚨 WebGL fallback still blocked by forceExplicitVoidReturn
packages/typegpu-three/src/typegpu-node.ts:193 still passes the resolved function code through forceExplicitVoidReturn. That helper assumes WGSL syntax: it looks for -> to detect an explicit return type and otherwise appends -> void after the first ). GLSL function declarations do not contain ->, so a signature such as float foo() is corrupted into float foo()-> void, which is invalid GLSL. This was raised in the previous pullfrog review and has not been addressed in this rebase.
Technical details
# forceExplicitVoidReturn corrupts GLSL signatures
## Affected sites
- packages/typegpu-three/src/typegpu-node.ts:193 — `forceExplicitVoidReturn(fnCode)` is applied to GLSL code
## Required outcome
- GLSL function code must not be passed through the WGSL-specific `forceExplicitVoidReturn` helper.
## Suggested approach
Skip `forceExplicitVoidReturn` when `webgl` is true, or detect whether the resolved code already has a return type in a language-agnostic way.Kimi K2 (free via Pullfrog for OSS) | 𝕏

No description provided.